#pragma once

#include <exception>
#include <typeinfo>
#include <vector>
#include <map>

namespace ccrtrtti
{
	void dump_progress();

	struct progress_info_t
	{
		enum memebr_type_e
		{
			constructor,
			destructor,
			method
		};
		type_info const *		type_descriptor;
		int						inheritance_level;
		memebr_type_e			type;				
	};
	
	typedef std::vector<progress_info_t> progress_vector_t;
	extern progress_vector_t	progress_vector;

	struct unwind_info_t
	{
		unwind_info_t( void const * to, void const * obo )
			: this_object( to )
			, onwing_base_object( obo )
			, constructed(0)
			, destructed(0)
		{}
		void const *	this_object;
		void const *	onwing_base_object;
		int	constructed, destructed;
	};
	typedef std::map<void const *,unwind_info_t> unwind_map_t;
	extern unwind_map_t	unwind_map;

	template<typename T>
	int	report_progress( T const * cpp_obj, progress_info_t::memebr_type_e t, int l )
	{
		cpp_obj->counter++;
		progress_info_t info;
		info.type_descriptor = &typeid( cpp_obj );
		info.inheritance_level = l;
		info.type = t;
		progress_vector.push_back( info );

		unwind_map_t::iterator itu = unwind_map.find( cpp_obj );
		if( itu == unwind_map.end() )
		{
			void const * parent = 0;
			try {
				parent = dynamic_cast<void const *>(cpp_obj);
			} 
			catch( std::__non_rtti_object const & ex )
			{
				printf("%s:%s\n", typeid(T).raw_name(), ex.what() );
			}

			unwind_info_t uinfo( cpp_obj, parent );

			std::pair<unwind_map_t::iterator,bool>
				ins_res = unwind_map.insert( 
				unwind_map_t::value_type( static_cast<void const *>(cpp_obj), uinfo ) );
			itu = ins_res.first;
		}

		switch( t )
		{
		case progress_info_t::constructor:
			itu->second.constructed += 1;
			break;
		case progress_info_t::destructor:
			itu->second.destructed += 1;
			break;
		}

		return l;
	}


#	define REPORT_CONSTRUCTOR report_progress( this, progress_info_t::constructor, l )

#	define REPORT_DESTRUCTOR report_progress(this, progress_info_t::destructor, level )

	class test_error_1 : public std::exception
	{
	public:
		test_error_1(const char* w = "test_error_1") throw() 
			: std::exception(w) {}
		virtual ~test_error_1() throw() {}
	};

	class test_class_a_throw_error_2 : public std::exception
	{
	public:
		test_class_a_throw_error_2(const char* w = "test_class_a_throw_error_2") throw() 
			: std::exception(w) {}
		virtual ~test_class_a_throw_error_2() throw() {}
	};
	
}



